﻿
#include "pqMyPropertyWidgetForProperty.h"

#include "pqPropertiesPanel.h"

#include "pqDoubleLineEdit.h"
#include "ui_cubewidget.h"
#include <QCheckBox>
#include <QGridLayout>
#include <QLabel>
#include <qpushbutton.h>

#include "CFMesh.h"
#include "Project.h"
#include "STLGeometry.h"
#include "easyloggingpp.h"
#include<QtConcurrent/QtConcurrent>
#include"pqProgressManager.h"
#include"pqApplicationCore.h"
#include "catalyst.hpp"
#include "BoundingBoxNodeName.h"
#include "MeshDictNodeName.h"

#include "FileHelper.hpp"

//-----------------------------------------------------------------------------
pqMyPropertyWidgetForProperty::pqMyPropertyWidgetForProperty(vtkSMProxy* smproxy,
                                                             vtkSMProperty* smproperty,
                                                             QWidget* parentObject)
  : Superclass(smproxy, parentObject)
{
  Ui::CubeWidget ui;
  ui.setupUi(this);
  this->setShowLabel(false);

  //全局加载样式表
  QFile styleFile(":/pangu/Plugin/Resource/Style/DefaultTheme.qss");
  if (styleFile.open(QIODevice::ReadOnly))
  {
    QString string = styleFile.readAll();
    qApp->setStyleSheet(string);
  }
  
  FileHelper::relaPath2FullPath("./blueCFD", blueCFDPath);
  if (blueCFDPath.empty())
  {
    LOG(ERROR) << "blueCFDPath is empty";
    return ;
  }

  workSpace = "./workspace/demo";

  //geometryPath = blueCFDPath + "/driver/driver.stl";

  geometryPath = blueCFDPath + "/e175/E175.stl";


  this->addPropertyLink(
    ui.txt_xNeg, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("XNeg"));
  this->addPropertyLink(
    ui.txt_xPos, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("XPos"));
  this->addPropertyLink(
    ui.txt_yNeg, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("YNeg"));
  this->addPropertyLink(
    ui.txt_yPos, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("YPos"));
  this->addPropertyLink(
    ui.txt_zNeg, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("ZNeg"));
  this->addPropertyLink(
    ui.txt_zPos, "text2", SIGNAL(textChangedAndEditingFinished()), smproxy->GetProperty("ZPos"));

  this->addPropertyLink(ui.txt_cellSize,
                        "text2",
                        SIGNAL(textChangedAndEditingFinished()),
                        smproxy->GetProperty("CellSize"));
 
  this->addPropertyLink(ui.txt_maxCellSize,
                        "text2",
                        SIGNAL(textChangedAndEditingFinished()),
                        smproxy->GetProperty("MaxCellSize"));

  connect(ui.myPushButton,
          &QPushButton::clicked,
          this,
          [=]() {

            BoxModel bm;
            bm.xNegativeLength = ui.txt_xNeg->text().toDouble();
            bm.xPositiveLength = ui.txt_xPos->text().toDouble();

            bm.yNegativeLength = ui.txt_yNeg->text().toDouble();
            bm.yPositiveLength = ui.txt_yPos->text().toDouble();

            bm.zNegativeLength = ui.txt_zNeg->text().toDouble();
            bm.zPositiveLength = ui.txt_zPos->text().toDouble();
            MeshModel mm;

            mm.cellSize = ui.txt_cellSize->text().toDouble();
            mm.maxCellSize = ui.txt_maxCellSize->text().toDouble();
            mm.bm = bm;

            projectMeth(mm);
          });
}
//-----------------------------------------------------------------------------
pqMyPropertyWidgetForProperty::~pqMyPropertyWidgetForProperty() = default;

void pqMyPropertyWidgetForProperty::projectMeth(MeshModel mm)
{

    //200, 100, 50, 50, 50, 50
    // cellsize 1.0f
    // 10
  //1.creat project
  //Project project;
  project.CreateWorkSpace(workSpace);
  project.SetBlueCFDEnv(blueCFDPath);

  //2.add geometry
  std::shared_ptr<Geometry> geometry = getGeometry(project);
  project.AddGeometry(geometry);

  //3.init workspace
  conduit_cpp::Node meshDictNode;
  setMeshDictNode(geometry, mm.maxCellSize, meshDictNode);

  conduit_cpp::Node boundingBoxNode;
  boundingBoxNode[name_boundingBox_xNLength] = mm.bm.xNegativeLength;
  boundingBoxNode[name_boundingBox_xPLength] = mm.bm.xPositiveLength;
  boundingBoxNode[name_boundingBox_yNLength] = mm.bm.yNegativeLength;
  boundingBoxNode[name_boundingBox_yPLength] = mm.bm.yPositiveLength;
  boundingBoxNode[name_boundingBox_zNLength] = mm.bm.zNegativeLength;
  boundingBoxNode[name_boundingBox_zPLength] = mm.bm.zPositiveLength;
  project.GenerateBoundBoxing(boundingBoxNode);

  //************driverCase*******************//
  //setLocalRefinement("driver.*", 0.05f, meshDictNode);
  //setBoxRefinement("tank_box", "box", 0.005f, 3.353f, -0.724f, 0.09f, 0.36f, 0.04f, 0.24f, 0.0f, meshDictNode);//BOX:cellSize,boxCenter,lengthx,lengthy,lengthz,ThicknessRefinement
  //setBoxRefinement("car_tail", "box", 0.1f, 4.0f, 0.0f, 0.0f, 10.0f, 3.0f, 3.2f, 0.0f, meshDictNode);//BOX:cellSize,boxCenter,lengthx,lengthy,lengthz,ThicknessRefinement
  //std::string edge_geometry_path0 = blueCFDPath + "/driver/driver_featureEdges_angle10.vtk";//线几何加密0
  //setGeometryRefinement("edge0", "edge", 0.005, edge_geometry_path0, 0, meshDictNode); //cellSize,geometryPath,Thickness
  //std::string surface_geometry_path0 = blueCFDPath + "/driver/underbody_intakeS.stl";//面几何加密0
  //setGeometryRefinement("surface0", "surface", 0.002, surface_geometry_path0, 0.03, meshDictNode);//cellSize,geometryPath,Thickness
  //setBoundaryLayer("driver.*", 5, 1.5, 0.002, meshDictNode);
  //************driverCase*******************//

  //****************e175Case******************//
  setLocalRefinement("BODY", 1.0f, meshDictNode);
  setLocalRefinement("SMALLFOIL", 1.0f, meshDictNode);
  setLocalRefinement("BIGFOIL", 1.0f, meshDictNode);
  setSphereRefinement("sphere0", "sphere", 3.0f, -50.0f, 0.0f, 0.0f,70.0f, 0.0f, meshDictNode);//SPHERE:cellSize,sphereCenter,Radius,ThicknessRefinement
  //setConeRefinement("cone0", "cone", 3.0f, -105.0f, 0.0f, 0.0f,-200.0f,0.0f, 0.0f, 50.0f, 50.0f,0.0f,meshDictNode);//CONE:cellSize,p0,p1,R0,R1,ThicknessRefinement
  //setLineRefinement("line0", "line", 3.0f, -240.0f, 0.0f, -40.0f,-240.0, 0.0f, 40.0f,10.0f, meshDictNode);//LINE:cellSize,p0,p1,ThicknessRefinement
  std::string edge_geometry_path1 = blueCFDPath + "/e175/refEdge_spline.vtk"; //线几何加密1
  setGeometryRefinement("edge1", "edge", 1, edge_geometry_path1, 0, meshDictNode); 
  //std::string surface_geometry_path1 = blueCFDPath + "/e175/refSurfaceSphere.stl";//面几何加密1
  //setGeometryRefinement("surface1", "surface", 1, surface_geometry_path1, 0, meshDictNode); 
  setBoundaryLayer("BODY", 5, 1.5, 0.2, meshDictNode);
  setBoundaryLayer("SMALLFOIL", 5, 1.5, 0.2, meshDictNode);
  setBoundaryLayer("BIGFOIL", 5, 1.5, 0.2, meshDictNode);
  //****************e175Case******************//
 

  // 7 .initWorkSpace
  project.InitWorkSpace(meshDictNode);

  //add mesh
  std::shared_ptr<Mesh> mesh = std::make_shared<CFMesh>(*geometry);
  project.AddMesh(mesh);

  //build mesh
  connect(mesh.get(),
          &Mesh::writeProcessRate,
          this,
          [=](QString processMsg, int rate) { setProcessRate(processMsg + "...", rate);
          });
  project.BuildMesh();
}

std::shared_ptr<Geometry> pqMyPropertyWidgetForProperty::getGeometry(Project& project)
{
  std::shared_ptr<Geometry> geometry = std::make_shared<STLGeometry>();
  geometry->Load(geometryPath);
  project.AddGeometry(geometry);
  return geometry;
}

void pqMyPropertyWidgetForProperty::setMeshDictNode(const std::shared_ptr<Geometry>& geometry,
                                                    const double& maxCellSize,
                                                    conduit_cpp::Node& node)
{
  node[name_surfaceFile] = geometry->GetStem() + "_box.fms";
  node[name_maxCellSize] = maxCellSize;
}

void pqMyPropertyWidgetForProperty::setLocalRefinement(const std::string& patchName,
                                                       const double& cellSize,
                                                       conduit_cpp::Node& node)
{
  node[name_localRef + "/" + patchName + "/" + name_cellSize] = cellSize;
}

void pqMyPropertyWidgetForProperty::setBoundaryLayer(const std::string& patchName,
                                                     const int& layerNumber,
                                                     const double& thicknessRatio,
                                                     const double& maxFirstLayerThickness,
                                                     conduit_cpp::Node& node)
{
  node[name_boundaryLayers + "/" + patchName + "/" + name_nLayers] = layerNumber;
  node[name_boundaryLayers + "/" + patchName + "/" + name_thicknessRatio] = thicknessRatio;
  node[name_boundaryLayers + "/" + patchName + "/" + name_maxFirstLayerThikness] = maxFirstLayerThickness;
}

void pqMyPropertyWidgetForProperty::setBoxRefinement(const std::string& name,
                                                     const std::string& type,
                                                     const double& cellSize,
                                                     const double& centerX,
                                                     const double& centerY,
                                                     const double& centerZ,
                                                     const double& xlength,
                                                     const double& ylength,
                                                     const double& zlength,
                                                     const double& refinementThickness,
                                                     conduit_cpp::Node& node)
{
  node[name_objRef + "/" + name +  "/" + name_type] = type;
  node[name_objRef + "/" + name +  "/" + name_cellSize] = cellSize;
  node[name_objRef + "/" + name + "/" + name_box_center + "/" + name_x] = centerX;
  node[name_objRef + "/" + name + "/" + name_box_center + "/" +name_y] = centerY;
  node[name_objRef + "/" + name + "/" + name_box_center + "/" + name_z] = centerZ;
  node[name_objRef + "/" + name +  "/" + name_lengthX] = xlength;
  node[name_objRef + "/" + name +  "/" + name_lengthY] = ylength;
  node[name_objRef + "/" + name +  "/" + name_lengthZ] = zlength;
  node[name_objRef + "/" + name +  "/" + name_refThickness] = refinementThickness;
}

void pqMyPropertyWidgetForProperty::setProcessRate(QString processMsg,int rate) {
  QFuture future = QtConcurrent::run(
    [=]() {
      pqProgressManager* pmManager = pqApplicationCore::instance()->getProgressManager();
      if (rate==0)
      {
        pmManager->setEnableProgress(true);
        pmManager->unblockEvents(true);   
      }
      pmManager->setProgress(processMsg, rate);
      if (rate==100)
      {
        Sleep(1000);
        pmManager->setEnableProgress(false);
      }
     
    });
 
}
void pqMyPropertyWidgetForProperty::setSphereRefinement(const std::string& name,
                                                        const std::string& type,
                                                        const double& cellSize,
                                                        const double& sphereCenterX,
                                                        const double& sphereCenterY,
                                                        const double& sphereCenterZ,
                                                        const double& sphereRadius,
                                                        const double& refinementThickness,
                                                        conduit_cpp::Node& node)
{
  node[name_objRef + "/" + name +  "/" + name_type] = type;
  node[name_objRef + "/" + name +  "/" + name_cellSize] = cellSize;
  node[name_objRef + "/" + name + "/" + name_sphere_center + "/" + name_x] = sphereCenterX;
  node[name_objRef + "/" + name + "/" + name_sphere_center + "/" + name_y] = sphereCenterY;
  node[name_objRef + "/" + name + "/" + name_sphere_center + "/" + name_z] = sphereCenterZ;
  node[name_objRef + "/" + name + "/" + name_sphere_radius] = sphereRadius;
  node[name_objRef + "/" + name +  "/" + name_refThickness] = refinementThickness;
}
void pqMyPropertyWidgetForProperty::setConeRefinement(const std::string& name,
                                                        const std::string& type,
                                                        const double& cellSize,
                                                        const double& cone_point0X,
                                                        const double& cone_point0Y,
                                                        const double& cone_point0Z,
                                                        const double& cone_point1X,
                                                        const double& cone_point1Y,
                                                        const double& cone_point1Z,
                                                        const double& cone_radius0,
                                                        const double& cone_radius1,
                                                        const double& refinementThickness,
                                                        conduit_cpp::Node& node)
{
  node[name_objRef + "/" + name + "/" + name_type] = type;
  node[name_objRef + "/" + name + "/" + name_cellSize] = cellSize;
  node[name_objRef + "/" + name + "/" + name_cone_point0 + "/" + name_x] = cone_point0X;
  node[name_objRef + "/" + name + "/" + name_cone_point0 + "/" + name_y] = cone_point0Y;
  node[name_objRef + "/" + name + "/" + name_cone_point0 + "/" + name_z] = cone_point0Z;
  node[name_objRef + "/" + name + "/" + name_cone_point1 + "/" + name_x] = cone_point1X;
  node[name_objRef + "/" + name + "/" + name_cone_point1 + "/" + name_y] = cone_point1Y;
  node[name_objRef + "/" + name + "/" + name_cone_point1 + "/" + name_z] = cone_point1Z;
  node[name_objRef + "/" + name + "/" + name_cone_radius0] = cone_radius0;
  node[name_objRef + "/" + name + "/" + name_cone_radius1] = cone_radius1;
  node[name_objRef + "/" + name + "/" + name_refThickness] = refinementThickness;
}
void pqMyPropertyWidgetForProperty::setLineRefinement(const std::string& name,
                                                      const std::string& type,
                                                      const double& cellSize,
                                                      const double& line_point0X,
                                                      const double& line_point0Y,
                                                      const double& line_point0Z,
                                                      const double& line_point1X,
                                                      const double& line_point1Y,
                                                      const double& line_point1Z,
                                                      const double& refinementThickness,
                                                      conduit_cpp::Node& node)
{
  node[name_objRef + "/" + name + "/" + name_type] = type;
  node[name_objRef + "/" + name + "/" + name_cellSize] = cellSize;
  node[name_objRef + "/" + name + "/" + name_line_point0 + "/" + name_x] = line_point0X;
  node[name_objRef + "/" + name + "/" + name_line_point0 + "/" + name_y] = line_point0Y;
  node[name_objRef + "/" + name + "/" + name_line_point0 + "/" + name_z] = line_point0Z;
  node[name_objRef + "/" + name + "/" + name_line_point1 + "/" + name_x] = line_point1X;
  node[name_objRef + "/" + name + "/" + name_line_point1 + "/" + name_y] = line_point1Y;
  node[name_objRef + "/" + name + "/" + name_line_point1 + "/" + name_z] = line_point1Z;
  node[name_objRef + "/" + name + "/" + name_refThickness] = refinementThickness;
}
void pqMyPropertyWidgetForProperty::setGeometryRefinement(const std::string& name,
                                                        const std::string& geo_type,
                                                        const double& cellSize,
                                                        const std::string& geo_input_name,
                                                        const double& refinementThickness,
                                                        conduit_cpp::Node& node)
{
  node[name_geoRef + "/" + name + "/" + name_geo_type] = geo_type;
  node[name_geoRef + "/" + name + "/" + name_cellSize] = cellSize;
  node[name_geoRef + "/" + name + "/" + name_geoInputName] = geo_input_name;
  node[name_geoRef + "/" + name + "/" + name_refThickness] = refinementThickness;
}